home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / trace / tcpdump-2.2.1 / print-snmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-19  |  22.1 KB  |  1,044 lines

  1. /*
  2.  * Copyright (c) 1990, by John Robert LoVerso.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by John Robert LoVerso.
  11.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  12.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  13.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  14.  *
  15.  * This implementaion has been influenced by the CMU SNMP release,
  16.  * by Steve Waldbusser.  However, this shares no code with that system.
  17.  * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
  18.  * Earlier forms of this implemention were derived and/or inspired by an
  19.  * awk script originally written by C. Philip Wood of LANL (but later
  20.  * heavily modified by John Robert LoVerso).  The copyright notice for
  21.  * that work is preserved below, even though it may not rightly apply
  22.  * to this file.
  23.  *
  24.  * This started out as a very simple program, but the incremental decoding
  25.  * (into the BE structure) complicated things.
  26.  *
  27.  #            Los Alamos National Laboratory
  28.  #
  29.  #    Copyright, 1990.  The Regents of the University of California.
  30.  #    This software was produced under a U.S. Government contract
  31.  #    (W-7405-ENG-36) by Los Alamos National Laboratory, which is
  32.  #    operated by the    University of California for the U.S. Department
  33.  #    of Energy.  The U.S. Government is licensed to use, reproduce,
  34.  #    and distribute this software.  Permission is granted to the
  35.  #    public to copy and use this software without charge, provided
  36.  #    that this Notice and any statement of authorship are reproduced
  37.  #    on all copies.  Neither the Government nor the University makes
  38.  #    any warranty, express or implied, or assumes any liability or
  39.  #    responsibility for the use of this software.
  40.  #    @(#)snmp.awk.x    1.1 (LANL) 1/15/90
  41.  */
  42. #ifndef lint
  43. static char rcsid[] =
  44.     "@(#) $Id: print-snmp.c,v 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso $ (jlv)";
  45. #endif
  46.  
  47. #include <sys/param.h>
  48. #include <sys/types.h>
  49. #include <stdio.h>
  50. #include <ctype.h>
  51.  
  52. #include "interface.h"
  53. #include "addrtoname.h"
  54.  
  55. /*
  56.  * Universal ASN.1 types
  57.  * (we only care about the tag values for those allowed in the Internet SMI)
  58.  */
  59. char *Universal[] = {
  60.     "U-0",
  61.     "Boolean",
  62.     "Integer",
  63. #define INTEGER 2
  64.     "Bitstring",
  65.     "String",
  66. #define STRING 4
  67.     "Null",
  68. #define ASN_NULL 5
  69.     "ObjID",
  70. #define OBJECTID 6
  71.     "ObjectDes",
  72.     "U-8","U-9","U-10","U-11",    /* 8-11 */
  73.     "U-12","U-13","U-14","U-15",    /* 12-15 */
  74.     "Sequence",
  75. #define SEQUENCE 16
  76.     "Set"
  77. };
  78.  
  79. /*
  80.  * Application-wide ASN.1 types from the Internet SMI and their tags
  81.  */
  82. char *Application[] = {
  83.     "IpAddress",
  84. #define IPADDR 0
  85.     "Counter",
  86. #define COUNTER 1
  87.     "Gauge",
  88. #define GAUGE 2
  89.     "TimeTicks",
  90. #define TIMETICKS 3
  91.     "Opaque"
  92. };
  93.  
  94. /*
  95.  * Context-specific ASN.1 types for the SNMP PDUs and their tags
  96.  */
  97. char *Context[] = {
  98.     "GetRequest",
  99. #define GETREQ 0
  100.     "GetNextRequest",
  101. #define GETNEXTREQ 1
  102.     "GetResponse",
  103. #define GETRESP 2
  104.     "SetRequest",
  105. #define SETREQ 3
  106.     "Trap"
  107. #define TRAP 4
  108. };
  109.  
  110. /*
  111.  * Private ASN.1 types
  112.  * The Internet SMI does not specify any
  113.  */
  114. char *Private[] = {
  115.     "P-0"
  116. };
  117.  
  118. /*
  119.  * error-status values for any SNMP PDU
  120.  */
  121. char *ErrorStatus[] = {
  122.     "noError",
  123.     "tooBig",
  124.     "noSuchName",
  125.     "badValue",
  126.     "readOnly",
  127.     "genErr"
  128. };
  129. #define DECODE_ErrorStatus(e) \
  130.     ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
  131.     ? ErrorStatus[e] : (sprintf(errbuf, "err=%d", e), errbuf))
  132.  
  133. /*
  134.  * generic-trap values in the SNMP Trap-PDU
  135.  */
  136. char *GenericTrap[] = {
  137.     "coldStart",
  138.     "warmStart",
  139.     "linkDown",
  140.     "linkUp",
  141.     "authenticationFailure",
  142.     "egpNeighborLoss",
  143.     "enterpriseSpecific"
  144. #define GT_ENTERPRISE 7
  145. };
  146. #define DECODE_GenericTrap(t) \
  147.     ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
  148.     ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf))
  149.  
  150. /*
  151.  * ASN.1 type class table
  152.  * Ties together the preceding Universal, Application, Context, and Private
  153.  * type definitions.
  154.  */
  155. #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
  156. struct {
  157.     char    *name;
  158.     char    **Id;
  159.     int    numIDs;
  160. } Class[] = {
  161.     defineCLASS(Universal),
  162. #define    UNIVERSAL    0
  163.     defineCLASS(Application),
  164. #define    APPLICATION    1
  165.     defineCLASS(Context),
  166. #define    CONTEXT        2
  167.     defineCLASS(Private),
  168. #define    PRIVATE        3
  169. };
  170.  
  171. /*
  172.  * defined forms for ASN.1 types
  173.  */
  174. char *Form[] = {
  175.     "Primitive",
  176. #define PRIMITIVE    0
  177.     "Constructed",
  178. #define CONSTRUCTED    1
  179. };
  180.  
  181. /*
  182.  * A structure for the OID tree for the compiled-in MIB.
  183.  * This is stored as a general-order tree.
  184.  */
  185. struct obj {
  186.     char    *desc;            /* name of object */
  187.     u_char    oid;            /* sub-id following parent */
  188.     u_char    type;            /* object type (unused) */
  189.     struct obj *child, *next;    /* child and next sibling pointers */
  190. } *objp = NULL;
  191.  
  192. /*
  193.  * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
  194.  * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
  195.  * a value for `mibroot'.
  196.  *
  197.  * In particluar, this is gross, as this is including initialized structures,
  198.  * and by right shouldn't be an "include" file.
  199.  */
  200. #include "mib.h"
  201.  
  202. /*
  203.  * This defines a list of OIDs which will be abreviated on output.
  204.  * Currently, this includes the prefixes for the Internet MIB, the
  205.  * private enterprises tree, and the experimental tree.
  206.  */
  207. struct obj_abrev {
  208.     char *prefix;            /* prefix for this abrev */
  209.     struct obj *node;        /* pointer into object table */
  210.     char *oid;            /* ASN.1 encoded OID */
  211. } obj_abrev_list[] = {
  212. #ifndef NO_ABREV_MIB
  213.     /* .iso.org.dod.internet.mgmt.mib */
  214.     { "",    &_mib_obj,         "\53\6\1\2\1" },
  215. #endif
  216. #ifndef NO_ABREV_ENTER
  217.     /* .iso.org.dod.internet.private.enterprises */
  218.     { "E:",    &_enterprises_obj,    "\53\6\1\4\1" },
  219. #endif
  220. #ifndef NO_ABREV_EXPERI
  221.     /* .iso.org.dod.internet.experimental */
  222.     { "X:",    &_experimental_obj,    "\53\6\1\3" },
  223. #endif
  224.     { 0,0,0 }
  225. };
  226.  
  227. /*
  228.  * This is used in the OID print routine to walk down the object tree
  229.  * rooted at `mibroot'.
  230.  */
  231. #define OBJ_PRINT(o, suppressdot) \
  232. { \
  233.     if (objp) { \
  234.         do { \
  235.             if ((o) == objp->oid) \
  236.                 break; \
  237.         } while (objp = objp->next); \
  238.     } \
  239.     if (objp) { \
  240.         printf(suppressdot?"%s":".%s", objp->desc); \
  241.         objp = objp->child; \
  242.     } else \
  243.         printf(suppressdot?"%u":".%u", (o)); \
  244. }
  245.  
  246. /*
  247.  * This is the definition for the Any-Data-Type storage used purely for
  248.  * temporary internal representation while decoding an ASN.1 data stream.
  249.  */
  250. struct be {
  251.     unsigned long asnlen;
  252.     union {
  253.         caddr_t raw;
  254.         long integer;
  255.         unsigned long uns;
  256.         unsigned char *str;
  257.     } data;
  258.     unsigned char form, class, id;        /* tag info */
  259.     u_char type;
  260. #define BE_ANY        255
  261. #define BE_NONE        0
  262. #define BE_NULL        1
  263. #define BE_OCTET    2
  264. #define BE_OID        3
  265. #define BE_INT        4
  266. #define BE_UNS        5
  267. #define BE_STR        6
  268. #define BE_SEQ        7
  269. #define BE_INETADDR    8
  270. #define BE_PDU        9
  271. };
  272.  
  273. /*
  274.  * Defaults for SNMP PDU components
  275.  */
  276. #define DEF_COMMUNITY "public"
  277. #define DEF_VERSION 0
  278.  
  279. /*
  280.  * constants for ASN.1 decoding
  281.  */
  282. #define OIDMUX 40
  283. #define ASNLEN_INETADDR 4
  284. #define ASN_SHIFT7 7
  285. #define ASN_SHIFT8 8
  286. #define ASN_BIT8 0x80
  287. #define ASN_LONGLEN 0x80
  288.  
  289. #define ASN_ID_BITS 0x1f
  290. #define ASN_FORM_BITS 0x20
  291. #define ASN_FORM_SHIFT 5
  292. #define ASN_CLASS_BITS 0xc0
  293. #define ASN_CLASS_SHIFT 6
  294.  
  295. #define ASN_ID_EXT 0x1f        /* extension ID in tag field */
  296.  
  297. /*
  298.  * truncated==1 means the packet was complete, but we don't have all of
  299.  * it to decode.
  300.  */
  301. static int truncated;
  302. #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
  303.  
  304. /*
  305.  * This decodes the next ASN.1 object in the stream pointed to by "p"
  306.  * (and of real-length "len") and stores the intermediate data in the
  307.  * provided BE object.
  308.  *
  309.  * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
  310.  * O/w, this returns the number of bytes parsed from "p".
  311.  */
  312. int
  313. asn1_parse(p, len, elem)
  314.     register u_char *p;
  315.     int len;
  316.     struct be *elem;
  317. {
  318.     unsigned char form, class, id;
  319.     int indent=0, i, hdr;
  320.     char *classstr;
  321.  
  322.     elem->asnlen = 0;
  323.     elem->type = BE_ANY;
  324.     if (len < 1) {
  325.         ifNotTruncated puts("[nothing to parse], stdout");
  326.         return -1;
  327.     }
  328.  
  329.     /*
  330.      * it would be nice to use a bit field, but you can't depend on them.
  331.      *  +---+---+---+---+---+---+---+---+
  332.      *  + class |frm|        id         |
  333.      *  +---+---+---+---+---+---+---+---+
  334.      *    7   6   5   4   3   2   1   0
  335.      */
  336.     id = *p & ASN_ID_BITS;        /* lower 5 bits, range 00-1f */
  337. #ifdef notdef
  338.     form = (*p & 0xe0) >> 5;    /* move upper 3 bits to lower 3 */
  339.     class = form >> 1;        /* bits 7&6 -> bits 1&0, range 0-3 */
  340.     form &= 0x1;            /* bit 5 -> bit 0, range 0-1 */
  341. #else
  342.     form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
  343.     class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
  344. #endif
  345.     elem->form = form;
  346.     elem->class = class;
  347.     elem->id = id;
  348.     if (vflag)
  349.         printf("|%.2x", *p);
  350.     p++; len--; hdr = 1;
  351.     /* extended tag field */
  352.     if (id == ASN_ID_EXT) {
  353.         for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
  354.             if (vflag)
  355.                 printf("|%.2x", *p);
  356.             id += *p & ~ASN_BIT8;
  357.         }
  358.         if (len == 0 && *p & ASN_BIT8) {
  359.             ifNotTruncated fputs("[Xtagfield?]", stdout);
  360.             return -1;
  361.         }
  362.     }
  363.     if (len < 1) {
  364.         ifNotTruncated fputs("[no asnlen]", stdout);
  365.         return -1;
  366.     }
  367.     elem->asnlen = *p;
  368.     if (vflag)
  369.         printf("|%.2x", *p);
  370.     p++; len--; hdr++;
  371.     if (elem->asnlen & ASN_BIT8) {
  372.         int noct = elem->asnlen % ASN_BIT8;
  373.         elem->asnlen = 0;
  374.         if (len < noct) {
  375.             ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
  376.             return -1;
  377.         }
  378.         for (; noct-- > 0; len--, hdr++) {
  379.             if (vflag)
  380.                 printf("|%.2x", *p);
  381.             elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
  382.         }
  383.     }
  384.     if (len < elem->asnlen) {
  385.         if (!truncated) {
  386.             printf("[len%d<asnlen%u]", len, elem->asnlen);
  387.             return -1;
  388.         }
  389.         /* maybe should check at least 4? */
  390.         elem->asnlen = len;
  391.     }
  392.     if (form >= sizeof(Form)/sizeof(Form[0])) {
  393.         ifNotTruncated printf("[form?%d]", form);
  394.         return -1;
  395.     }
  396.     if (class >= sizeof(Class)/sizeof(Class[0])) {
  397.         ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
  398.         return -1;
  399.     }
  400.     if (id >= Class[class].numIDs) {
  401.         ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
  402.             Class[class].name, id);
  403.         return -1;
  404.     }
  405.  
  406.     switch (form) {
  407.     case PRIMITIVE:
  408.         switch (class) {
  409.         case UNIVERSAL:
  410.             switch (id) {
  411.             case STRING:
  412.                 elem->type = BE_STR;
  413.                 elem->data.str = p;
  414.                 break;
  415.  
  416.             case INTEGER: {
  417.                 register long data;
  418.                 elem->type = BE_INT;
  419.                 data = 0;
  420.  
  421.                 if (*p & ASN_BIT8)    /* negative */
  422.                     data = -1;
  423.                 for (i = elem->asnlen; i-- > 0; p++)
  424.                     data = (data << ASN_SHIFT8) | *p;
  425.                 elem->data.integer = data;
  426.                 break;
  427.             }
  428.  
  429.             case OBJECTID:
  430.                 elem->type = BE_OID;
  431.                 elem->data.raw = (caddr_t)p;
  432.                 break;
  433.  
  434.             case ASN_NULL:
  435.                 elem->type = BE_NULL;
  436.                 elem->data.raw = NULL;
  437.                 break;
  438.  
  439.             default:
  440.                 elem->type = BE_OCTET;
  441.                 elem->data.raw = (caddr_t)p;
  442.                 printf("[P/U/%s]",
  443.                     Class[class].Id[id]);
  444.                 break;
  445.             }
  446.             break;
  447.  
  448.         case APPLICATION:
  449.             switch (id) {
  450.             case IPADDR:
  451.                 elem->type = BE_INETADDR;
  452.                 elem->data.raw = (caddr_t)p;
  453.                 break;
  454.  
  455.             case COUNTER:
  456.             case GAUGE:
  457.             case TIMETICKS: {
  458.                 register unsigned long data;
  459.                 elem->type = BE_UNS;
  460.                 data = 0;
  461.                 for (i = elem->asnlen; i-- > 0; p++)
  462.                     data = (data << 8) + *p;
  463.                 elem->data.uns = data;
  464.                 break;
  465.             }
  466.  
  467.             default:
  468.                 elem->type = BE_OCTET;
  469.                 elem->data.raw = (caddr_t)p;
  470.                 printf("[P/A/%s]",
  471.                     Class[class].Id[id]);
  472.                 break;
  473.             }
  474.             break;
  475.  
  476.         default:
  477.             elem->type = BE_OCTET;
  478.             elem->data.raw = (caddr_t)p;
  479.             printf("[P/%s/%s]",
  480.                 Class[class].name, Class[class].Id[id]);
  481.             break;
  482.         }
  483.         break;
  484.  
  485.     case CONSTRUCTED:
  486.         switch (class) {
  487.         case UNIVERSAL:
  488.             switch (id) {
  489.             case SEQUENCE:
  490.                 elem->type = BE_SEQ;
  491.                 elem->data.raw = (caddr_t)p;
  492.                 break;
  493.  
  494.             default:
  495.                 elem->type = BE_OCTET;
  496.                 elem->data.raw = (caddr_t)p;
  497.                 printf("C/U/%s", Class[class].Id[id]);
  498.                 break;
  499.             }
  500.             break;
  501.  
  502.         case CONTEXT:
  503.             elem->type = BE_PDU;
  504.             elem->data.raw = (caddr_t)p;
  505.             break;
  506.  
  507.         default:
  508.             elem->type = BE_OCTET;
  509.             elem->data.raw = (caddr_t)p;
  510.             printf("C/%s/%s",
  511.                 Class[class].name, Class[class].Id[id]);
  512.             break;
  513.         }
  514.         break;
  515.     }
  516.     p += elem->asnlen;
  517.     len -= elem->asnlen;
  518.     return elem->asnlen + hdr;
  519. }
  520.  
  521. /*
  522.  * Display the ASN.1 object represented by the BE object.
  523.  * This used to be an integral part of asn1_parse() before the intermediate
  524.  * BE form was added.
  525.  */
  526. void
  527. asn1_print(elem)
  528.     struct be *elem;
  529. {
  530.     u_char *p = (u_char *)elem->data.raw;
  531.     u_long asnlen = elem->asnlen;
  532.     int i;
  533.  
  534.     switch (elem->type) {
  535.  
  536.     case BE_OCTET:
  537.         for (i = asnlen; i-- > 0; p++);
  538.             printf("_%.2x", *p);
  539.         break;
  540.  
  541.     case BE_NULL:
  542.         break;
  543.  
  544.     case BE_OID: {
  545.     int o = 0, first = -1, i = asnlen;
  546.  
  547.         if (!nflag && asnlen > 2) {
  548.             struct obj_abrev *a = &obj_abrev_list[0];
  549.             for (; a->node; a++) {
  550.                 if (!memcmp(a->oid, p, strlen(a->oid))) {
  551.                     objp = a->node->child;
  552.                     i -= strlen(a->oid);
  553.                     p += strlen(a->oid);
  554.                     fputs(a->prefix, stdout);
  555.                     first = 1;
  556.                     break;
  557.                 }
  558.             }
  559.         }
  560.         for (; i-- > 0; p++) {
  561.             o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
  562.             if (*p & ASN_LONGLEN)
  563.                 continue;
  564.  
  565.             /*
  566.              * first subitem encodes two items with 1st*OIDMUX+2nd
  567.              */
  568.             if (first < 0) {
  569.                 if (!nflag)
  570.                     objp = mibroot;
  571.                 first = 0;
  572.                 OBJ_PRINT(o/OIDMUX, first);
  573.                 o %= OIDMUX;
  574.             }
  575.             OBJ_PRINT(o, first);
  576.             if (--first < 0)
  577.                 first = 0;
  578.             o = 0;
  579.         }
  580.         break;
  581.     }
  582.  
  583.     case BE_INT:
  584.         printf("%ld", elem->data.integer);
  585.         break;
  586.  
  587.     case BE_UNS:
  588.         printf("%ld", elem->data.uns);
  589.         break;
  590.  
  591.     case BE_STR: {
  592.         register int printable = 1, first = 1;
  593.         u_char *p = elem->data.str;
  594.         for (i = asnlen; printable && i-- > 0; p++)
  595.             printable = isprint(*p) || isspace(*p);
  596.         p = elem->data.str;
  597.         if (printable)
  598.             (void)printfn(p, p+asnlen);
  599.         else
  600.             for (i = asnlen; i-- > 0; p++) {
  601.                 printf(first ? "%.2x" : "_%.2x", *p);
  602.                 first = 0;
  603.             }
  604.         break;
  605.     }
  606.  
  607.     case BE_SEQ:
  608.         printf("Seq(%d)", elem->asnlen);
  609.         break;
  610.  
  611.     case BE_INETADDR: {
  612.         char sep;
  613.         if (asnlen != ASNLEN_INETADDR)
  614.             printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
  615.         sep='[';
  616.         for (i = asnlen; i-- > 0; p++) {
  617.             printf("%c%u", sep, *p);
  618.             sep='.';
  619.         }
  620.         putchar(']');
  621.         break;
  622.     }
  623.  
  624.     case BE_PDU:
  625.         printf("%s(%d)",
  626.             Class[CONTEXT].Id[elem->id], elem->asnlen);
  627.         break;
  628.  
  629.     case BE_ANY:
  630.         fputs("[BE_ANY!?]", stdout);
  631.         break;
  632.  
  633.     default:
  634.         fputs("[be!?]", stdout);
  635.         break;
  636.     }
  637. }
  638.  
  639. #ifdef notdef
  640. /*
  641.  * This is a brute force ASN.1 printer: recurses to dump an entire structure.
  642.  * This will work for any ASN.1 stream, not just an SNMP PDU.
  643.  *
  644.  * By adding newlines and spaces at the correct places, this would print in
  645.  * Rose-Normal-Form.
  646.  *
  647.  * This is not currently used.
  648.  */
  649. void
  650. asn1_decode(p, length)
  651.     u_char *p;
  652.     int length;
  653. {
  654.     struct be elem;
  655.     int i = 0;
  656.  
  657.     while (i >= 0 && length > 0) {
  658.         i = asn1_parse(p, length, &elem);
  659.         if (i >= 0) {
  660.             fputs(" ", stdout);
  661.             asn1_print(&elem);
  662.             if (elem.type == BE_SEQ || elem.type == BE_PDU) {
  663.                 fputs(" {", stdout);
  664.                 asn1_decode(elem.data.raw, elem.asnlen);
  665.                 fputs(" }", stdout);
  666.             }
  667.             length -= i;
  668.             p += i;
  669.         }
  670.     }
  671. }
  672. #endif
  673.  
  674. /*
  675.  * General SNMP header
  676.  *    SEQUENCE {
  677.  *        version INTEGER {version-1(0)},
  678.  *        community OCTET STRING,
  679.  *        data ANY     -- PDUs
  680.  *    }
  681.  * PDUs for all but Trap: (see rfc1157 from page 15 on)
  682.  *    SEQUENCE {
  683.  *        request-id INTEGER,
  684.  *        error-status INTEGER,
  685.  *        error-index INTEGER,
  686.  *        varbindlist SEQUENCE OF
  687.  *            SEQUENCE {
  688.  *                name ObjectName,
  689.  *                value ObjectValue
  690.  *            }
  691.  *    }
  692.  * PDU for Trap:
  693.  *    SEQUENCE {
  694.  *        enterprise OBJECT IDENTIFIER,
  695.  *        agent-addr NetworkAddress,
  696.  *        generic-trap INTEGER,
  697.  *        specific-trap INTEGER,
  698.  *        time-stamp TimeTicks,
  699.  *        varbindlist SEQUENCE OF
  700.  *            SEQUENCE {
  701.  *                name ObjectName,
  702.  *                value ObjectValue
  703.  *            }
  704.  *    }
  705.  */
  706.  
  707. /*
  708.  * Decode SNMP varBind
  709.  */
  710. void
  711. varbind_print (pduid, np, length, error)
  712.     u_char pduid, *np;
  713.     int length, error;
  714. {
  715.     struct be elem;
  716.     int count = 0, index;
  717.  
  718.     /* Sequence of varBind */
  719.     if ((count = asn1_parse(np, length, &elem)) < 0)
  720.         return;
  721.     if (elem.type != BE_SEQ) {
  722.         fputs("[!SEQ of varbind]", stdout);
  723.         asn1_print(&elem);
  724.         return;
  725.     }
  726.     if (count < length)
  727.         printf("[%d extra after SEQ of varbind]", length - count);
  728.     /* descend */
  729.     length = elem.asnlen;
  730.     np = (u_char *)elem.data.raw;
  731.  
  732.     for (index = 1; length > 0; index++) {
  733.         u_char *vbend;
  734.         int vblength;
  735.  
  736.         if (!error || index == error)
  737.             fputs(" ", stdout);
  738.  
  739.         /* Sequence */
  740.         if ((count = asn1_parse(np, length, &elem)) < 0)
  741.             return;
  742.         if (elem.type != BE_SEQ) {
  743.             fputs("[!varbind]", stdout);
  744.             asn1_print(&elem);
  745.             return;
  746.         }
  747.         vbend = np + count;
  748.         vblength = length - count;
  749.         /* descend */
  750.         length = elem.asnlen;
  751.         np = (u_char *)elem.data.raw;
  752.  
  753.         /* objName (OID) */
  754.         if ((count = asn1_parse(np, length, &elem)) < 0)
  755.             return;
  756.         if (elem.type != BE_OID) {
  757.             fputs("[objName!=OID]", stdout);
  758.             asn1_print(&elem);
  759.             return;
  760.         }
  761.         if (!error || index == error)
  762.             asn1_print(&elem);
  763.         length -= count;
  764.         np += count;
  765.  
  766.         if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
  767.                 fputs("=", stdout);
  768.  
  769.         /* objVal (ANY) */
  770.         if ((count = asn1_parse(np, length, &elem)) < 0)
  771.             return;
  772.         if (pduid == GETREQ || pduid == GETNEXTREQ) {
  773.             if (elem.type != BE_NULL) {
  774.                 fputs("[objVal!=NULL]", stdout);
  775.                 asn1_print(&elem);
  776.             }
  777.         } else
  778.             if (error && index == error && elem.type != BE_NULL)
  779.                 fputs("[err objVal!=NULL]", stdout);
  780.             if (!error || index == error)
  781.                 asn1_print(&elem);
  782.  
  783.         length = vblength;
  784.         np = vbend;
  785.     }
  786. }
  787.  
  788. /*
  789.  * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
  790.  */
  791. void
  792. snmppdu_print (pduid, np, length)
  793.     u_char pduid, *np;
  794.     int length;
  795. {
  796.     struct be elem;
  797.     int count = 0, error;
  798.  
  799.     /* reqId (Integer) */
  800.     if ((count = asn1_parse(np, length, &elem)) < 0)
  801.         return;
  802.     if (elem.type != BE_INT) {
  803.         fputs("[reqId!=INT]", stdout);
  804.         asn1_print(&elem);
  805.         return;
  806.     }
  807.     /* ignore the reqId */
  808.     length -= count;
  809.     np += count;
  810.  
  811.     /* errorStatus (Integer) */
  812.     if ((count = asn1_parse(np, length, &elem)) < 0)
  813.         return;
  814.     if (elem.type != BE_INT) {
  815.         fputs("[errorStatus!=INT]", stdout);
  816.         asn1_print(&elem);
  817.         return;
  818.     }
  819.     error = 0;
  820.     if ((pduid == GETREQ || pduid == GETNEXTREQ)
  821.         && elem.data.integer != 0) {
  822.         char errbuf[10];
  823.         printf("[errorStatus(%s)!=0]", 
  824.             DECODE_ErrorStatus(elem.data.integer));
  825.     } else if (elem.data.integer != 0) {
  826.         char errbuf[10];
  827.         printf(" %s", DECODE_ErrorStatus(elem.data.integer));
  828.         error = elem.data.integer;
  829.     }
  830.     length -= count;
  831.     np += count;
  832.  
  833.     /* errorIndex (Integer) */
  834.     if ((count = asn1_parse(np, length, &elem)) < 0)
  835.         return;
  836.     if (elem.type != BE_INT) {
  837.         fputs("[errorIndex!=INT]", stdout);
  838.         asn1_print(&elem);
  839.         return;
  840.     }
  841.     if ((pduid == GETREQ || pduid == GETNEXTREQ)
  842.         && elem.data.integer != 0)
  843.         printf("[errorIndex(%d)!=0]", elem.data.integer);
  844.     else if (elem.data.integer != 0) {
  845.         if (!error)
  846.             printf("[errorIndex(%d) w/o errorStatus]",
  847.                 elem.data.integer);
  848.         else {
  849.             printf("@%d", elem.data.integer);
  850.             error = elem.data.integer;
  851.         }
  852.     } else if (error) {
  853.         fputs("[errorIndex==0]", stdout);
  854.         error = 0;
  855.     }
  856.     length -= count;
  857.     np += count;
  858.  
  859.     varbind_print(pduid, np, length, error);
  860.     return;
  861. }
  862.  
  863. /*
  864.  * Decode SNMP Trap PDU
  865.  */
  866. void
  867. trap_print (np, length)
  868.     u_char *np;
  869.     int length;
  870. {
  871.     struct be elem;
  872.     int count = 0, generic;
  873.  
  874.     putchar(' ');
  875.  
  876.     /* enterprise (oid) */
  877.     if ((count = asn1_parse(np, length, &elem)) < 0)
  878.         return;
  879.     if (elem.type != BE_OID) {
  880.         fputs("[enterprise!=OID]", stdout);
  881.         asn1_print(&elem);
  882.         return;
  883.     }
  884.     asn1_print(&elem);
  885.     length -= count;
  886.     np += count;
  887.  
  888.     putchar(' ');
  889.  
  890.     /* agent-addr (inetaddr) */
  891.     if ((count = asn1_parse(np, length, &elem)) < 0)
  892.         return;
  893.     if (elem.type != BE_INETADDR) {
  894.         fputs("[agent-addr!=INETADDR]", stdout);
  895.         asn1_print(&elem);
  896.         return;
  897.     }
  898.     asn1_print(&elem);
  899.     length -= count;
  900.     np += count;
  901.  
  902.     /* generic-trap (Integer) */
  903.     if ((count = asn1_parse(np, length, &elem)) < 0)
  904.         return;
  905.     if (elem.type != BE_INT) {
  906.         fputs("[generic-trap!=INT]", stdout);
  907.         asn1_print(&elem);
  908.         return;
  909.     }
  910.     generic = elem.data.integer;
  911.     {
  912.         char buf[10];
  913.         printf(" %s", DECODE_GenericTrap(generic));
  914.     }
  915.     length -= count;
  916.     np += count;
  917.  
  918.     /* specific-trap (Integer) */
  919.     if ((count = asn1_parse(np, length, &elem)) < 0)
  920.         return;
  921.     if (elem.type != BE_INT) {
  922.         fputs("[specific-trap!=INT]", stdout);
  923.         asn1_print(&elem);
  924.         return;
  925.     }
  926.     if (generic != GT_ENTERPRISE) {
  927.         if (elem.data.integer != 0)
  928.             printf("[specific-trap(%d)!=0]", elem.data.integer);
  929.     } else
  930.         printf(" s=%d", elem.data.integer);
  931.     length -= count;
  932.     np += count;
  933.  
  934.     putchar(' ');
  935.  
  936.     /* time-stamp (TimeTicks) */
  937.     if ((count = asn1_parse(np, length, &elem)) < 0)
  938.         return;
  939.     if (elem.type != BE_UNS) {            /* XXX */
  940.         fputs("[time-stamp!=TIMETICKS]", stdout);
  941.         asn1_print(&elem);
  942.         return;
  943.     }
  944.     asn1_print(&elem);
  945.     length -= count;
  946.     np += count;
  947.  
  948.     varbind_print (TRAP, np, length, 0);
  949.     return;
  950. }
  951.  
  952. /*
  953.  * Decode SNMP header and pass on to PDU printing routines
  954.  */
  955. void
  956. snmp_print (np, length)
  957.     u_char *np;
  958.     int length;
  959. {
  960.     struct be elem, pdu;
  961.     int count = 0;
  962.  
  963.     truncated = 0;
  964.  
  965.     /* truncated packet? */
  966.     if (np + length > snapend) {
  967.         truncated = 1;
  968.         length = snapend - np;
  969.     }
  970.  
  971.     putchar(' ');
  972.  
  973.     /* initial Sequence */
  974.     if ((count = asn1_parse(np, length, &elem)) < 0)
  975.         return;
  976.     if (elem.type != BE_SEQ) {
  977.         fputs("[!init SEQ]", stdout);
  978.         asn1_print(&elem);
  979.         return;
  980.     }
  981.     if (count < length)
  982.         printf("[%d extra after iSEQ]", length - count);
  983.     /* descend */
  984.     length = elem.asnlen;
  985.     np = (u_char *)elem.data.raw;
  986.     /* Version (Integer) */
  987.     if ((count = asn1_parse(np, length, &elem)) < 0)
  988.         return;
  989.     if (elem.type != BE_INT) {
  990.         fputs("[version!=INT]", stdout);
  991.         asn1_print(&elem);
  992.         return;
  993.     }
  994.     /* only handle version==0 */
  995.     if (elem.data.integer != DEF_VERSION) {
  996.         printf("[version(%d)!=0]", elem.data.integer);
  997.         return;
  998.     }
  999.     length -= count;
  1000.     np += count;
  1001.  
  1002.     /* Community (String) */
  1003.     if ((count = asn1_parse(np, length, &elem)) < 0)
  1004.         return;
  1005.     if (elem.type != BE_STR) {
  1006.         fputs("[comm!=STR]", stdout);
  1007.         asn1_print(&elem);
  1008.         return;
  1009.     }
  1010.     /* default community */
  1011.     if (strncmp(elem.data.str, DEF_COMMUNITY, sizeof(DEF_COMMUNITY)-1))
  1012.         /* ! "public" */
  1013.         printf("C=%.*s ", elem.asnlen, elem.data.str);
  1014.     length -= count;
  1015.     np += count;
  1016.  
  1017.     /* PDU (Context) */
  1018.     if ((count = asn1_parse(np, length, &pdu)) < 0)
  1019.         return;
  1020.     if (pdu.type != BE_PDU) {
  1021.         fputs("[no PDU]", stdout);
  1022.         return;
  1023.     }
  1024.     if (count < length)
  1025.         printf("[%d extra after PDU]", length - count);
  1026.     asn1_print(&pdu);
  1027.     /* descend into PDU */
  1028.     length = pdu.asnlen;
  1029.     np = (u_char *)pdu.data.raw;
  1030.  
  1031.     switch (pdu.id) {
  1032.     case TRAP:
  1033.         trap_print(np, length);
  1034.         break;
  1035.     case GETREQ:
  1036.     case GETNEXTREQ:
  1037.     case GETRESP:
  1038.     case SETREQ:
  1039.         snmppdu_print(pdu.id, np, length);
  1040.         break;
  1041.     }
  1042.     return;
  1043. }
  1044.